/*
 * Famon (http://code.google.com/p/famon/)
 * Copyright (c) 2010 Carl Crous.
 *
 * This file is part of Famon.
 *
 * Famon is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Famon is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Famon.  If not, see <http://www.gnu.org/licenses/>.
 */

package za.org.foobar.famon.frontend.client.ui;

import com.google.gwt.core.client.GWT;
import com.smartgwt.client.data.Criteria;
import com.smartgwt.client.data.DSCallback;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.DSOperationType;
import com.smartgwt.client.types.VerticalAlignment;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.*;
import com.smartgwt.client.widgets.grid.ColumnTree;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.NodeSelectedEvent;
import com.smartgwt.client.widgets.grid.events.NodeSelectedHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;
import org.gwtportlets.portlet.client.WidgetFactory;
import org.gwtportlets.portlet.smartgwt.client.DataTransferObject;
import org.gwtportlets.portlet.smartgwt.client.SmartPortlet;
import org.gwtportlets.portlet.smartgwt.client.SmartPortletDataSource;
import org.gwtportlets.portlet.smartgwt.client.SmartPortletFactory;
import za.org.foobar.famon.frontend.client.dto.*;
import za.org.foobar.famon.frontend.client.util.ClientUtil;

public class ApplicationManagerPortlet extends SmartPortlet {
    private DynamicForm applicationForm;
    private VLayout applicationEditPane;
    private ColumnTree columnTree;
    private HLayout layout;
    private VLayout editPane;
    private VLayout instanceEditPane;
    private DynamicForm instanceForm;
    private VLayout versionEditPane;
    private DynamicForm versionForm;
    private VLayout userEditPane;
    private DynamicForm userForm;
    private VLayout addUserEditPane;
    private DynamicForm addUserForm;
    private String applicationKey;
    private String applicationId;

    public ApplicationManagerPortlet() {
        layout = new HLayout(5);
        columnTree = createColumnTree();
        layout.addMember(columnTree);
        editPane = createEditPane();
        applicationEditPane = createEditPane("Application", ApplicationDto.getDataSource(this),
                applicationForm = new DynamicForm());
        instanceEditPane = createEditPane("Instance", ApplicationInstanceDto.getDataSource(this),
                instanceForm = new DynamicForm());
        versionEditPane = createEditPane("Version", ApplicationVersionDto.getDataSource(this),
                versionForm = new DynamicForm());
        userEditPane = createEditPane("User", ApplicationUserDto.getDataSource(this),
                userForm = new DynamicForm());
        addUserEditPane = createEditPane("Add User", ApplicationUserDto.getDataSource(this),
                addUserForm = new DynamicForm());
        initWidget(layout);
    }

    private ColumnTree createColumnTree() {
        final ColumnTree tree = new ColumnTree();
        tree.setDataSource(ApplicationTreeDto.getDataSource(this));
        tree.setAutoFetchData(true);
        tree.setFirstColumnTitle("Applications");
        tree.setShowHeaders(true);
        tree.setShowNodeCount(true);
        tree.setLoadDataOnDemand(true);
        tree.setShowOpenIcons(false);
        tree.setShowDropIcons(false);
        tree.setNodeIcon(null);
        tree.setFolderIcon(null);

        tree.addNodeSelectedHandler(new NodeSelectedHandler() {
            public void onNodeSelected(NodeSelectedEvent event) {
                ListGridRecord record = event.getColumn().getSelectedRecord();
                String name = record.getAttributeAsString("name");
                GWT.log(name, null);
                String key = record.getAttributeAsString("key");
                String id = record.getAttributeAsString("id");
                String type = record.getAttributeAsString("type");
                boolean canEdit = ClientUtil.falseIfNull(record.getAttributeAsBoolean("canEdit"));
                hideEditPane(instanceEditPane);
                hideEditPane(versionEditPane);
                hideEditPane(userEditPane);
                hideEditPane(applicationEditPane);
                hideEditPane(addUserEditPane);
                if (canEdit) {
                    if (type.equals(ApplicationTreeDto.Type.APPLICATION.name())) {
                        applicationKey = key;
                        applicationId = id;
                        showEditPane(applicationEditPane, applicationForm, key, null, null);
                    } else if (type.equals(ApplicationTreeDto.Type.OPTION.name())) {
                        if (name.equals("Users")) {
                            showEditPane(addUserEditPane, addUserForm, null, null, applicationId);
                        } else {
                            showEditPane(applicationEditPane, applicationForm, applicationKey, null, null);
                        }
                    } else {
                        if (type.equals(ApplicationTreeDto.Type.INSTANCE.name())) {
                            showEditPane(instanceEditPane, instanceForm, key, null, null);
                        } else if (type.equals(ApplicationTreeDto.Type.VERSION.name())) {
                            showEditPane(versionEditPane, versionForm, key, null, null);
                        } else if (type.equals(ApplicationTreeDto.Type.USER.name())) {
                            showEditPane(userEditPane, userForm, key, id, null);
                        }
                        event.cancel();
                    }
                }
            }
        });
        return tree;
    }

    private VLayout createEditPane() {
        VLayout editPane = new VLayout(5);
        editPane.setWidth(200);
        editPane.setAlign(VerticalAlignment.TOP);
        return editPane;
    }

    private VLayout createEditPane(String name, SmartPortletDataSource ds, final DynamicForm form) {
        final VLayout pane = new VLayout(5);
        pane.addMember(new Label(name + ":"));
        form.setDataSource(ds);
        form.setAutoFetchData(false);

        if (name.equals("User")) {
            FormItem applicationUserIdField = new HiddenItem("id");
            SelectItem roleField = new SelectItem("role", "Role");
            roleField.setValueField("id");
            roleField.setDisplayField("value");
            roleField.setOptionDataSource(EnumDto.getDataSource(this, "Role"));
            roleField.setAutoFetchData(true);
            form.setFields(applicationUserIdField, roleField);
        } else if (name.equals("Add User")) {
            FormItem applicationIdField = new HiddenItem("applicationId");
            SelectItem userSelect = new SelectItem("userId", "User");
            userSelect.setValueField("id");
            userSelect.setDisplayField("nickname");
            userSelect.setPickListWidth(250);
            userSelect.setOptionDataSource(UserDto.getDataSource(this));
            form.setFields(applicationIdField, userSelect);
        } else {
            FormItem nameField = new TextItem("name", "Name");
            nameField.setRequired(true);
            if (name.equals("Application")) {
                BooleanItem privateField = new BooleanItem();
                privateField.setName("isPrivate");
                privateField.setTitle("Private");
                form.setFields(nameField, privateField);
            } else {
                form.setFields(nameField);
            }
        }

        pane.addMember(form);

        if (name.equals("User")) {
            pane.addMember(createButton("Save", form, pane, DSOperationType.UPDATE));
            pane.addMember(createButton("Remove", form, pane, DSOperationType.REMOVE));
        } else if (name.equals("Add User")) {
            pane.addMember(createButton("Add", form, pane, DSOperationType.ADD));
        } else {
            pane.addMember(createButton("Save", form, pane, DSOperationType.UPDATE));
        }
        return pane;
    }

    private IButton createButton(String title, final DynamicForm form, final VLayout pane,
                                 final DSOperationType operationType) {
        IButton saveButton = new IButton(title);
        saveButton.setLayoutAlign(Alignment.CENTER);
        saveButton.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                form.setSaveOperationType(operationType);
                form.saveData(createDSCallback(pane));
            }
        });
        return saveButton;
    }
    private DSCallback createDSCallback(final VLayout pane) {
        return new DSCallback() {
            public void execute(DSResponse response, Object rawData, DSRequest request) {
                hideEditPane(pane);
                columnTree.removeFromParent();
                columnTree.markForDestroy();
                columnTree = createColumnTree();
                layout.addMember(columnTree, 0);
            }
        };
    }

    private void showEditPane() {
        if (!layout.hasMember(editPane)) {
            layout.addMember(editPane);
        }
    }

    private void hideEditPane() {
        if (layout.hasMember(editPane)) {
            layout.removeMember(editPane);
        }
    }

    private void showEditPane(VLayout pane, DynamicForm form, String key, String id, String applicationId) {
        if (!editPane.hasMember(pane)) {
            editPane.addMember(pane);
        }
        form.clearErrors(true);

        Criteria criteria = new Criteria();
        if (applicationId != null) {
            criteria.addCriteria("applicationId", applicationId);
        }
        if (id != null) {
            criteria.addCriteria("id", id);
        } else if (key != null) {
            criteria.addCriteria("key", key);
        }
        form.fetchData(criteria);
        showEditPane();
    }

    private void hideEditPane(VLayout pane) {
        hideEditPane();
        if (editPane.hasMember(pane)) {
            editPane.removeMember(pane);
        }
    }

    public WidgetFactory createWidgetFactory() {
        return new Factory();
    }

    public static class Factory extends SmartPortletFactory<ApplicationManagerPortlet> {
        public Factory() {
        }

        public Factory(ApplicationManagerPortlet p) {
            super(p);
        }

        public ApplicationManagerPortlet createWidget() {
            return new ApplicationManagerPortlet();
        }

        @Override
        public DataTransferObject createDto() {
            if (ApplicationTreeDto.DATA_SOURCE_ID.equals(dataSourceId)) {
                return new ApplicationTreeDto();
            } else if (UserDto.DATA_SOURCE_ID.equals(dataSourceId)) {
                return new UserDto();
            } else if (ApplicationDto.DATA_SOURCE_ID.equals(dataSourceId)) {
                return new ApplicationDto();
            } else if (ApplicationInstanceDto.DATA_SOURCE_ID.equals(dataSourceId)) {
                return new ApplicationInstanceDto();
            } else if (ApplicationVersionDto.DATA_SOURCE_ID.equals(dataSourceId)) {
                return new ApplicationVersionDto();
            } else if (ApplicationUserDto.DATA_SOURCE_ID.equals(dataSourceId)) {
                return new ApplicationUserDto();
            }
            return null;
        }
    }
}
